package copor

import (
	"database/sql"
	"errors"
	"reflect"
	"time"

	"github.com/jinzhu/copier"
)

// 当前特殊处理主要是处理struct{} 和 []struct{}

// ChangeFunc 自定义转换函数 将原结构体字段值value转换成自己需要的值并返回
// 例：return value.(time.Time).Format("2006-01-02 15:04:05")
type ChangeFunc func(value interface{}) interface{}

var specialChange = make(map[string]bool)        // 特殊字段类型转换
var changeFuncList = make(map[string]ChangeFunc) // 特殊类型自定义转换函数

const (
	SpecialTimeToStr = "specialTimeToString" // 时间型转时间字符串  "2006-01-02 15:04:05"
)

func init() {
	// 当前只有一个特殊处理，默认添加，后期特殊处理增多后，再去除
	AddSpecial(SpecialTimeToStr)
}

// AddSpecial 添加特殊类型转换
func AddSpecial(change string, args ...ChangeFunc) {
	specialChange[change] = true
	if len(args) > 0 {
		changeFuncList[change] = args[0]
	}
}

// StopSpecial 暂停特殊字段转换
func StopSpecial(change string) {
	specialChange[change] = false
}

// Copy 主体复制函数
func Copy(toValue interface{}, fromValue interface{}) error {
	// 复制
	err := copier.Copy(toValue, fromValue)
	if err != nil {
		return err
	}
	// 特殊字段类型处理
	for k, v := range specialChange {
		if v {
			switch k {
			case SpecialTimeToStr:
				err = specialTimeChangeStr(toValue, fromValue)
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// 日期转指定格式字符串
func specialTimeChangeStr(toValue interface{}, fromValue interface{}) (err error) {
	var isSlice bool = false
	var amount = 1
	from := indirect(reflect.ValueOf(fromValue))
	to := indirect(reflect.ValueOf(toValue))
	fromType, _ := indirectType(from.Type())

	if from.Kind() == reflect.Slice || to.Kind() == reflect.Slice {
		// 切片数组
		isSlice = true
		if from.Kind() == reflect.Slice {
			amount = from.Len()
		}
	}
	for i := 0; i < amount; i++ {
		var dest, source reflect.Value

		if isSlice {
			// source
			if from.Kind() == reflect.Slice {
				source = indirect(from.Index(i))
			} else {
				source = indirect(from)
			}
			// dest 由于执行过基础复制，to数组已生成，直接使用子项操作
			dest = indirect(to.Index(i))
		} else {
			source = indirect(from)
			dest = indirect(to)
		}

		fromTypeFields := deepFields(fromType)
		for _, field := range fromTypeFields {
			name := field.Name
			fromField := source.FieldByName(name)
			if fromField.Kind() == reflect.Struct && (fromField.Type().String() == "time.Time" || fromField.Type().String() == "sql.NullTime") {
				// 找到日期格式字段
				toField := dest.FieldByName(name)
				if toField.IsValid() {
					if toField.CanSet() && toField.Kind() == reflect.String {
						// 目标字段为字符串格式
						if changeFuncList[SpecialTimeToStr] != nil {
							// 执行自定义函数
							value := changeFuncList[SpecialTimeToStr](fromField.Interface())
							v, ok := value.(string)
							if !ok {
								return errors.New("返回的不是字符串格式")
							}
							toField.SetString(v)
						} else {
							switch fromField.Type().String() {
							case "time.Time":
								toField.SetString(fromField.Interface().(time.Time).Format("2006-01-02 15:04:05"))
							case "sql.NullTime":
								if fromField.Interface().(sql.NullTime).Valid {
									toField.SetString(fromField.Interface().(sql.NullTime).Time.Format("2006-01-02 15:04:05"))
								} else { // 空时间，返回空字符串
									toField.SetString("")
								}
							}
						}
					}
				}
			}
		}
	}
	return
}

// 之后可做纯自定义类型转换 和 根据字段名称自定义转换
